const assert = require('assert')
const { Op } = require('sequelize')
const { genWhereObj } = require('./helper')
const R = require('ramda')
const omitWhere = R.omit(['where'])

class SequelizeRepository {
  constructor({ coverter, model }) {
    assert(model, '没有模型哦')
    assert(coverter, '没有转换器哦')
    this.coverter = coverter
    this.model = model
  }

  async paginate({ page, size, ...where }, options, likeFields = []) {
    const data = await this.model.paginate({
      page,
      size,
      where: genWhereObj(likeFields, where),
      ...omitWhere(options),
    })
    data.docs = this.coverter.toEntityList(data.docs)
    return data
  }

  async findAll(where, options, likeFields = []) {
    const data = await this.model.findAll({
      where: genWhereObj(likeFields, where),
      ...omitWhere(options),
    })
    return this.coverter.toEntityList(data)
  }

  getUsername(currentUser) {
    return currentUser ? currentUser.username : 'anno'
  }

  async findById(id, options) {
    return this.coverter.toEntity(await this.model.findByPk(id, options))
  }

  async findOne(options) {
    return this.coverter.toEntity(await this.model.findOne(options))
  }

  async create(entity, { currentUser, ...options }) {
    const value = this.coverter.toDatabase(entity)
    const data = await this.model.create(
      {
        ...value,
        createdBy: this.getUsername(currentUser),
      },
      options
    )
    return this.coverter.toEntity(data)
  }

  async update(entity, { currentUser, ...options }, audit = true) {
    const values = this.coverter.toDatabase(entity)
    if (audit) {
      Object.assign(values, {
        updatedBy: this.getUsername(currentUser),
      })
    }
    await this.model.update(values, {
      where: {
        id: entity.id,
      },
      ...omitWhere(options),
    })
  }

  async remove(entity, { currentUser, ...options }) {
    await this.model.update(
      {
        deletedBy: this.getUsername(currentUser),
      },
      {
        where: { id: entity.id },
        ...omitWhere(options),
      }
    )
    await this.model.destroy({
      where: { id: entity.id },
      ...omitWhere(options),
    })
  }

  async batchRemove(ids = [], options) {
    await this.model.update(
      {
        deletedBy: this.getUsername(currentUser),
      },
      {
        where: { id: { [Op.in]: ids } },
        ...omitWhere(options),
      }
    )
    await this.model.destroy({
      where: {
        id: {
          [Op.in]: ids,
        },
      },
      ...omitWhere(options),
    })
  }
}

module.exports = SequelizeRepository
